import {delay, designComponent, getComponentCls, reactive, useClassCache, useModel} from "@peryl/react-compose";
import {$ai, AiChatBox, Alert, Layout, LayoutSection} from "plain-design";
import {MonacoEditor} from "../components/MonacoEditor";
import {iAiHistory} from "plain-design/src/packages/components/$ai";
import {defer, DFD} from "@peryl/utils/defer";
import {PlainObject} from "@peryl/utils/event";
import {http} from "../../modules/plain-design/http";
import {doNothing} from "@peryl/utils/doNothing";
import {CodeGenPromptIntent} from "./code-gen.prompt.intent";
import {CodeGenPromptList} from "./code-gen.prompt.list";
import {CodeGenPromptForm} from "./code-gen.prompt.form";

export const AICodeEditor = designComponent({
  name: 'ai-code-editor',
  props: {
    modelValue: { type: String },
    chatBoxWidth: { type: Number, default: 375 },
    readonly: { type: Boolean, default: false },
  },
  emits: {
    onUpdateModelValue: (val: any) => true,
  },
  setup({ props, event }) {

    const classes = useClassCache(() => [getComponentCls('ai-code-editor')]);

    const model = useModel(() => props.modelValue, event.emit.onUpdateModelValue);

    const state = reactive({
      editorLanguage: 'javascript' as any,
      /*增加一个变量标识，用来标记当前是否处于读取AI生成代码，某些情况下，AI流式输出内容的时候是没有代码的，这种情况下忽略不处理流式更新代码内容*/
      isReading: false,
    });

    const handler = {
      /*获取AI生成代码所涉及的模块*/
      getModules: (() => {
        let dfd: DFD<PlainObject[]> | undefined = undefined;
        return () => {
          if (!dfd) {
            dfd = defer<any>();
            http.post<{ list: PlainObject[] }>('/module/list', { all: true }).then(data => {dfd!.resolve(data.list);});
          }
          return dfd!.promise;
        };
      })(),
      /*处理AI流式返回内容*/
      handleReceive: ({ fullText }: { fullText?: string }) => {
        const lines: string[] = fullText?.split('\n') ?? [];
        let codeLines: string[] = [];
        lines.forEach((str, lineIndex) => {

          if (['```tsx', '```jsx', '```js', '```html',].indexOf(str.toLowerCase()) > -1) {
            state.editorLanguage = block2language[str.toLowerCase().slice(3)] ?? 'javascript';
            state.isReading = true;
          } else if (str === '```') {
            if (state.isReading) {
              state.isReading = false;
              model.value = codeLines.slice(0, lineIndex - 1).join('\n');
            }
          } else {
            if (state.isReading) {
              codeLines.push(str);
            }
          }
        });
        if (state.isReading) {
          model.value = codeLines.join('\n');
        }
      },
      /*在发送用户消息给AI，流式生成代码之前，先判断用户当前意图是否是要生成代码，生成的代码涉及到哪个模块*/
      beforeSendUserContent: async ({ userContent, messages }: { userContent: string, messages: iAiHistory[] }): Promise<any> => {
        const moduleList = await handler.getModules();
        const { message: intentMessage } = await $ai.chatSystem(userContent, CodeGenPromptIntent({
          moduleDescription: moduleList.map(i => `${i.label}(${i.code})`).join(',')
        }));
        const messageData = JSON.parse(intentMessage);
        if ('module' in messageData && messageData.module === 'none') {
          console.log('no module', messageData, messageData);
          messages.push(
            { role: 'user', content: userContent },
            { role: 'system', content: `你需要告诉用户，找不到复合描述的业务模块` }
          );
          return;
        }
        if (messageData.type === 'list') {
          const targetModule = moduleList.find(i => i.code == messageData.module);
          console.log('list', messageData, targetModule);
          if (!!targetModule) {
            const prompt = CodeGenPromptList({ moduleConfig: targetModule.moduleConfig, });
            console.log(prompt);
            messages.push({ role: 'system', content: prompt });
          } else {
            messages.push(
              { role: 'user', content: userContent },
              { role: 'system', content: `你需要告诉用户，找不到复合描述的业务模块` }
            );
          }
        }
        if (messageData.type === 'form') {
          const targetModule = moduleList.find(i => i.code == messageData.module);
          console.log('form', messageData, targetModule);
          if (!!targetModule) {
            const prompt = CodeGenPromptForm({ moduleConfig: targetModule.moduleConfig, });
            console.log(prompt);
            messages.push({ role: 'system', content: prompt });
          } else {
            messages.push(
              { role: 'user', content: userContent },
              { role: 'system', content: `你需要告诉用户，找不到复合描述的业务模块` }
            );
          }
        }
        if (messageData.type === 'error') {
          messages.push({ role: 'system', content: `你需要回复用户：${messageData.error}` });
        }
        if (messageData.type === 'none') {doNothing();}
      },
      /*流式生成结束的时候，标记结束*/
      onFinish: () => {
        state.isReading = false;
      },
    };

    return () => (
      <Layout fullHeight className={classes.value}>
        <LayoutSection fixedInner>
          <MonacoEditor
            key={state.editorLanguage}
            language={state.editorLanguage}
            v-model={model.value}
            readonly={props.readonly}
          />
        </LayoutSection>
        <LayoutSection position="right" modelValue={props.chatBoxWidth}>
          <AiChatBox
            fitHeight
            handleReceive={handler.handleReceive}
            beforeSendUserContent={handler.beforeSendUserContent}
            v-slots={{
              prepend: () => <>
                <Alert icon={null} size="mini">
                  <div>1. 帮我生成一个React增删改查的示例代码，用TSX开发；</div>
                </Alert>
              </>
            }}
          />
        </LayoutSection>
      </Layout>
    );
  },
});

const block2language: Record<string, string | undefined> = {
  jsx: 'javascript',
  js: 'javascript',
  tsx: 'typescript',
  html: 'html',
  css: 'css',
  json: 'json',
};
